import * as path from 'node:path';

import { Inject, Injectable, Logger, NotFoundException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as fse from 'fs-extra';
import * as lodash from 'lodash';

import { type IConfiguration } from '../../config/configuration';
import { type IScheDuleRule } from '../../interface.d';
import { fullScreenChrome } from '../../utils';
import { DataFactory } from '../common/global/dataFactory/dataFactory.service';

// import { PredefinedNetworkConditions } from 'puppeteer-core';
// const slow3G = PredefinedNetworkConditions['Slow 4G'];

type IJson = {
  douyinPngList: string[];
  name: string;
  tags: string[];
};

@Injectable()
export class DouyinService {
  @Inject()
  private globalService: DataFactory;

  private readonly logger = new Logger(DouyinService.name);

  @Inject(ConfigService)
  private configService: ConfigService<IConfiguration>;

  async run(rule: IScheDuleRule) {
    const { cacheDirName, jsonConfigPath } = rule;

    const browser = await this.globalService.createBroswer(cacheDirName);

    const [page] = await browser.pages();

    page.on('error', error => {
      this.logger.error(error);
      throw new NotFoundException(error);
    });

    await page.setRequestInterception(true);

    page.on('request', interceptedRequest => {
      if (interceptedRequest.isInterceptResolutionHandled()) return;

      const url = interceptedRequest.url();

      if (url.endsWith('.png') || url.endsWith('.jpg') || url.endsWith('output.mp4')) interceptedRequest.abort();
      else interceptedRequest.continue();
    });

    await page.goto('https://creator.douyin.com/', { waitUntil: 'networkidle0' });

    page.off('request');

    await page.setRequestInterception(false);

    fullScreenChrome();

    if (page.url().includes('/creator-micro/home')) {
      this.logger.verbose('登录成功');
    } else {
      this.logger.error('未登录');
      await browser.close();
      return;
    }

    await page.bringToFront();

    this.logger.verbose('进入图文');

    await Promise.all([
      page.locator('div::-p-text(发布图文 )').click({ delay: 1500 }),
      page.waitForNavigation({ waitUntil: 'networkidle0' }),
    ]);

    this.logger.verbose('如有上次未发布的图文则点击放弃');

    const giveupBtn = await page.$('span::-p-text(放弃)');
    await giveupBtn?.click({ delay: 5000 });
    await giveupBtn?.dispose();

    // const configJsonPath = path.join('/Users/kenny/Desktop/t_01', '介入放射学', 'douyin', 'douyin.json');

    const desktopPath = this.globalService.getDesktopPath();

    const { douyinPngList, name, tags } = <IJson>fse.readJSONSync(jsonConfigPath);
    const images = douyinPngList.map(i => path.join(desktopPath, i.replace(/[\\//]/gi, path.sep)));

    const fistImgFile = images.splice(0, 1);

    // console.log('AT-[ images &&&&&********** ]', images);

    this.logger.verbose('上传第一张图片');
    const uploadBtn = await page.waitForSelector('input[type=file]');
    uploadBtn.uploadFile(...fistImgFile);

    await page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 0 });

    this.logger.verbose('等待编辑图片元素出现');
    await page.locator('div::-p-text(编辑图片)').setTimeout(0).wait();

    this.logger.verbose('添加标题');
    const titleInput = await page.waitForSelector('input[type=text][placeholder="添加作品标题"]');
    await titleInput.type(name);
    await titleInput.dispose();

    this.logger.verbose('输入标签');
    const descBtn = await page.waitForSelector('.editor-kit-container');
    await descBtn?.scrollIntoView();
    await descBtn?.focus();

    this.logger.verbose('循环输入标签');

    const tagUrlPattern = 'challengesug/?source=challenge';
    for (const tag of tags.slice(0, 5)) {
      // await page.keyboard.type(`#${tag}`);

      // await page.waitForResponse(res => res.url().includes(tagUrlPattern) && res.status() === 200);

      await Promise.all([
        page.waitForResponse(res => res.url().includes(tagUrlPattern), { timeout: 0 }),
        page.keyboard.type(`#${tag}`),
      ]);

      this.logger.verbose('按下确认按钮');
      await page.keyboard.press('Enter', { delay: 2000 });
    }

    this.logger.verbose('将继续添加滚动到最顶部');
    const addImageBtn = await page.$('::-p-text(继续添加)');
    await addImageBtn?.scrollIntoView();

    this.logger.verbose('上传剩余全部图片');
    const [otherFileChooser] = await Promise.all([page.waitForFileChooser(), addImageBtn?.click()]);
    await otherFileChooser.accept(images);

    this.logger.verbose('等待所有的上传进度条都消失');
    await page.waitForSelector('.semi-progress', { hidden: true, timeout: 0 });

    this.logger.verbose('点击选择音乐按钮');
    await page.locator('span::-p-text(选择音乐)').setTimeout(0).click({ delay: 2000 });

    this.logger.verbose('等待音乐请求结果成功');
    // 初始化计数器
    let count = 0;

    const songUrlPattern = '/media/collection/song';
    // 使用 waitForResponse 监听请求
    await Promise.all([
      page.waitForResponse(async res => (res.url().includes(songUrlPattern) ? ++count >= 3 : false), { timeout: 0 }),
    ]);

    this.logger.verbose('随机滚动到一个tab然后点击一下');
    const musicTabs = await page.$$('.semi-overflow-list-scroll-wrapper > .semi-tabs-tab');
    const sampleMusicTab = lodash.sample(musicTabs);
    await sampleMusicTab?.scrollIntoView();
    await sampleMusicTab?.click({ delay: 5000 });
    await sampleMusicTab.dispose();

    this.logger.verbose('随机选择一首歌', '聚焦光标', '点击使用');
    const musicList = await page.$$('.semi-tabs-pane-motion-overlay > div:first-child > div:first-child > div');
    const sampleMusicItem = lodash.sample(musicList);
    await sampleMusicItem?.click({ delay: 5000 });

    // await page
    //   .waitForResponse(res => res.url().includes('/media/collection/song/'))
    //   // .catch(reason => this.logger.error(reason))
    //   .finally(() => Promise.resolve());

    await sampleMusicItem?.focus();
    await page.locator('.semi-button-content::-p-text(使用)').setTimeout(0).click({ delay: 2000 });

    this.logger.verbose('发布按钮滚动到可视区域');
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));

    this.logger.verbose('植入jquery');
    const serverPort = this.configService.get('serverPort');
    const { prefix } = this.configService.get<IConfiguration['staticServer']>('staticServer');
    const jqueryUrl = `http://127.0.0.1:${serverPort}/${prefix}/jquery.main.2.1.4.js`;

    await page.mainFrame().addScriptTag({ url: jqueryUrl });

    await page.evaluate(() => $('button:contains(发布):last').get(0).click());

    await page.waitForNavigation({ waitUntil: 'networkidle0' });

    this.logger.verbose('发布成功');

    await browser.close();
  }
}
